﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Windows.Input;
using System.Windows.Threading;
using System.Xml.Linq;
using CSharp.Libs.Koc.ItemClasses;
using CSharp.Libs.Misc;
using CSharp.Libs.WPF;



namespace CSharp.Libs.Koc.UserControls
{
    partial class KocKnightLevelerViewModel : ViewModelBase, IDisposable
    {
        #region declarations
        private Kernel _KRNL = null;
        private Dispatcher _DISP = null;

        private SeedHolder _scSeed = null;

        private RelayCommand _rcReadKnights = null;
        private RelayCommand _rcResetToDefaults = null;
        private RelayCommand _rcSkillUpnights = null;

        private ObservableCollection<KnightViewItem> _ocKnights = new ObservableCollection<KnightViewItem>();

        private LocalApplicationOptions _laoKnightOptions = null;
        private XElement _xeKnightOptions = null;

        private bool _fSeedExists = false;
        //private string _strKnightOptionsFullFileName = string.Concat(new FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName, "\\KnightOptions.xml");
        private string _strKnightOptionsFileName = "KnightOptions.xml";

        private const string ELEMENT_KNIGHT_OPTIONS = "KnightOptions";
        private const string ELEMENT_FBUID_SERVER = "FbUidServer";
        private const string ELEMENT_KNIGHT = "Knight";
        private const string ATTRIBUTE_KEY = "Key";
        private const string ATTRIBUTE_KNIGHT_ID = "KnightId";
        private const string ATTRIBUTE_KNIGHT_NAME = "KnightName";
        private const string ATTRIBUTE_SKILLUP = "Skillup";
        #endregion



        #region constructor / terminator
        public KocKnightLevelerViewModel(
            Dispatcher DISP,
            Kernel KRNL)
        {
            _KRNL = KRNL;
            _DISP = DISP;

            _initKernelControl();

            _KRNL.SC.SeedReceived += new SeedCollector.SeedReceivedEventHandler(SC_SeedReceived);

            _laoKnightOptions = new LocalApplicationOptions(_strKnightOptionsFileName);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                _saveKnightOptions();

                _xeKnightOptions = null;
                _laoKnightOptions = null;
                _ocKnights = null;
                _rcReadKnights = null;
                _DISP = null;
                _KRNL = null;
            }
            // get rid of unmanaged resources
        }

        ~KocKnightLevelerViewModel()
        {
            Dispose(false);

            _saveKnightOptions();
        }
        #endregion



        #region event handling
        void SC_SeedReceived(object sender, KernelModels.SeedReceivedEventArgs srea)
        {
            _checkSeedExists();
        }
        #endregion



        #region private functions
        /// <summary>_checkSeedExists</summary>
        /// <history>created  13.02.2012</history>
        private void _checkSeedExists()
        {
            _fSeedExists = false;

            try
            {
                if (_upiSelectedUser != null)
                {
                    //get key that seed would have in dictionary
                    string strSeedKey = _KRNL.SC.GetKey(_upiSelectedUser.FbUid, _intServerId.ToString());

                    //check if seed 
                    if (_KRNL.SC.Seeds.ContainsKey(strSeedKey))
                    {
                        _fSeedExists = true;
                    }
                }
            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }

            OnPropertyChanged("ReadKnights");
            OnPropertyChanged("CanReadKnights");
        }

        /// <summary>_readKnights</summary>
        /// <history>created  13.02.2012</history>
        /// <history>modified 15.02.2012: Switched to use SeedHolder class</history>
        private void _readKnights()
        {
            try
            {
                if (_upiSelectedUser != null)
                {
                    //get key that seed would have in dictionary
                    string strSeedKey = _KRNL.SC.GetKey(_upiSelectedUser.FbUid, _intServerId.ToString());

                    //check if seed 
                    if (_KRNL.SC.Seeds.ContainsKey(strSeedKey))
                    {
                        //Get seed
                        Hashtable htSeed = _KRNL.SC.Seeds[strSeedKey] as Hashtable;
                        if (htSeed != null)
                        {
                            _scSeed = new SeedHolder(_KRNL, htSeed);
                            _createKnightViewCollection();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }
        }

        /// <summary>_createKnightViewCollection</summary>
        /// <history>created  15.02.2012</history>
        private void _createKnightViewCollection()
        {
            try
            {
                Thread thr = new Thread((ParameterizedThreadStart)delegate
                {
                    if (_scSeed != null)
                    {
                        //clear collection
                        _clearKnights();

                        //get saved options 
                        _getCurrentKnightOptions();

                        //cycle through cities
                        foreach (KeyValuePair<string, CityKnightsItem> kvpCityKnights in _scSeed.CityKnights)
                        {
                            //Get city knights
                            CityKnightsItem CKI = kvpCityKnights.Value;

                            if (CKI != null)
                            {
                                //cycle through city knights
                                foreach (KeyValuePair<string, KnightItem> kvpKnight in CKI.Knights)
                                {
                                    //get knight
                                    KnightItem KI = kvpKnight.Value as KnightItem;
                                    if (KI != null)
                                    {
                                        //create KnightViewItem
                                        KnightViewItem KVI = new KnightViewItem(KI);
                                        _evaluateOtherValues(KVI);
                                        _AddKnight(KVI);
                                    }
                                }
                            }
                        }
                    }
                });
                thr.Start();
            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }
        }

        /// <summary>_evaluateOtherValues</summary>
        /// <param name="KVI"></param>
        /// <history>created  17.02.2012</history>
        private void _evaluateOtherValues(
            KnightViewItem KVI)
        {
            try
            {
                //CityName
                KVI.CityName = _scSeed.Cities[KVI.Knight.CityId.ToString()].CityName;

                //Level, Skillpoints
                //Original ausm script:
                //var level = parseInt(Math.sqrt(parseInt(knight.experience) / 75)) + 1;
                //var unpoints = level - parseInt(knight.skillPointsApplied);
                //var salary = (parseInt(knight.skillPointsApplied) + 1) * 20;
                KVI.Level = (Int64)(Math.Round(Math.Sqrt(KVI.Knight.Experience / 75))) + 1;
                KVI.UnassignedSkillPoints = KVI.Level - KVI.Knight.SkillPointsApplied;

                //Get role
                KVI.KnightRole = _getKnightRole(KVI.Knight.CityId, KVI.Knight.KnightId);

                //set skillups
                //see if knight has a saved option
                XElement xeKnightOption = _getKnightOptionByKnightId(KVI.Knight.KnightId.ToString());
                if (xeKnightOption != null &&
                    xeKnightOption.Attribute(ATTRIBUTE_SKILLUP) != null)
                {
                    KVI.SkillupPolitics = xeKnightOption.Attribute(ATTRIBUTE_SKILLUP).Value == KnightRoles.Foreman.GetHashCode().ToString();
                    KVI.SkillupCombat = xeKnightOption.Attribute(ATTRIBUTE_SKILLUP).Value == KnightRoles.Marshal.GetHashCode().ToString() ||
                        xeKnightOption.Attribute(ATTRIBUTE_SKILLUP).Value == KnightRoles.Unassigned.GetHashCode().ToString();
                    KVI.SkillupIntelligence = xeKnightOption.Attribute(ATTRIBUTE_SKILLUP).Value == KnightRoles.Alchemystic.GetHashCode().ToString();
                    KVI.SkillupResourcefulness = xeKnightOption.Attribute(ATTRIBUTE_SKILLUP).Value == KnightRoles.Steward.GetHashCode().ToString();
                }
                else
                {
                    _setDefaultSkillups(KVI);
                }
            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }
        }

        /// <summary>_setDefaultSkillups</summary>
        /// <param name="KVI"></param>
        /// <history>created  19.02.2012</history>
        private void _setDefaultSkillups(
            KnightViewItem KVI)
        {
            try
            {
                switch (KVI.KnightRole)
                {
                    case KnightRoles.Foreman:
                        KVI.SkillupPolitics = true;
                        break;

                    case KnightRoles.Marshal:
                        KVI.SkillupCombat = true;
                        break;

                    case KnightRoles.Alchemystic:
                        KVI.SkillupIntelligence = true;
                        break;

                    case KnightRoles.Steward:
                        KVI.SkillupResourcefulness = true;
                        break;

                    case KnightRoles.Unassigned:
                    default:
                        //Set max value 
                        if (KVI.Knight.Politics > KVI.Knight.Resourcefulness &&
                            KVI.Knight.Politics > KVI.Knight.Intelligence &&
                            KVI.Knight.Politics > KVI.Knight.Combat)
                        {
                            KVI.SkillupPolitics = true;
                        }
                        else if (KVI.Knight.Resourcefulness > KVI.Knight.Intelligence &&
                           KVI.Knight.Resourcefulness > KVI.Knight.Combat)
                        {
                            KVI.SkillupResourcefulness = true;
                        }
                        else if (KVI.Knight.Intelligence > KVI.Knight.Combat)
                        {
                            KVI.SkillupIntelligence = true;
                        }
                        else
                        {
                            KVI.SkillupCombat = true;
                        }
                        break;
                }

            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }
        }

        /// <summary>_getKnightRole</summary>
        /// <param name="CityID"></param>
        /// <param name="KnightID"></param>
        /// <returns></returns>
        /// <history>created  18.02.2012</history>
        private KnightRoles _getKnightRole(
            Int64 CityID,
            Int64 KnightID)
        {
            try
            {
                string strCityKey = "city" + CityID.ToString();

                if (_scSeed.CityLeaders.ContainsKey(strCityKey))
                {
                    CityLeadersItem CLI = _scSeed.CityLeaders[strCityKey];

                    if (CLI.Leaders.ContainsValue(KnightID))
                    {
                        foreach (KeyValuePair<KnightRoles, Int64> kvpLeader in CLI.Leaders)
                        {
                            if (kvpLeader.Value == KnightID)
                            {
                                return kvpLeader.Key;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }

            return KnightRoles.Unassigned;
        }

        /// <summary>_getKnightRoleOfItem</summary>
        /// <param name="KVI"></param>
        /// <returns></returns>
        /// <history>created  20.02.2012</history>
        private KnightRoles _getKnightRoleOfItem(
            KnightViewItem KVI)
        {
            try
            {
                if (KVI.SkillupPolitics)
                {
                    return KnightRoles.Foreman;
                }
                if (KVI.SkillupCombat)
                {
                    return KnightRoles.Marshal;
                }
                if (KVI.SkillupIntelligence)
                {
                    return KnightRoles.Alchemystic;
                }
                if (KVI.SkillupResourcefulness)
                {
                    return KnightRoles.Steward;
                }

            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }

            return KnightRoles.Unassigned;
        }

        /// <summary>_resetToDefaults</summary>
        /// <history>created  21.02.2012</history>
        private void _resetToDefaults()
        {
            foreach (KnightViewItem KVI in _ocKnights)
            {
                _setDefaultSkillups(KVI);
            }
        }

        /// <summary>_clearKnights</summary>
        /// <history>created  16.02.2012</history>
        private void _clearKnights()
        {
            _DISP.Invoke((Action)delegate
            {
                _ocKnights.Clear();
                OnPropertyChanged("Knights");
            });
        }

        /// <summary>_AddKnight</summary>
        /// <param name="KVI"></param>
        /// <history>created  16.02.2012</history>
        private void _AddKnight(
            KnightViewItem KVI)
        {
            _DISP.Invoke((Action)delegate
            {
                _ocKnights.Add(KVI);
                OnPropertyChanged("Knights");
            });
        }

        #region XML Options
        /// <summary>_getCurrentKnightOptions</summary>
        /// <history>created  21.02.2012</history>
        private void _getCurrentKnightOptions()
        {
            try
            {
                //get currnt Key
                string strKey = _KRNL.SC.GetKey(_upiSelectedUser.FbUid, _intServerId.ToString());

                //see if a local option is saved
                _xeKnightOptions = _laoKnightOptions.GetOptionXElement(ELEMENT_KNIGHT_OPTIONS);

                //if not, create a new one
                if (_xeKnightOptions == null)
                {
                    //create new
                    _xeKnightOptions = new XElement(ELEMENT_KNIGHT_OPTIONS,
                        new XElement(ELEMENT_FBUID_SERVER, new XAttribute(ATTRIBUTE_KEY, strKey)));
                }
            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }
        }

        /// <summary>_getFbUidServerIdNode</summary>
        /// <returns></returns>
        /// <history>created  21.02.2012</history>
        private XElement _getFbUidServerIdNode()
        {
            //get current key
            string strKey = _KRNL.SC.GetKey(_upiSelectedUser.FbUid, _intServerId.ToString());

            try
            {
                //get current Knightoptions for fbuid / server number combination
                IEnumerable<XElement> xeList = _xeKnightOptions.Descendants(ELEMENT_FBUID_SERVER).Where(
                    svrItem => string.Equals(svrItem.Attribute(ATTRIBUTE_KEY).Value, strKey, StringComparison.OrdinalIgnoreCase));

                //should only be one
                if (xeList.Count() > 0)
                {
                    XElement xeKnightOptions = xeList.First();
                    return xeKnightOptions;
                }
            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }

            //this should never be possible:
            return new XElement(ELEMENT_KNIGHT_OPTIONS,
                    new XElement(ELEMENT_FBUID_SERVER, new XAttribute(ATTRIBUTE_KEY, strKey)));
        }

        /// <summary>_getKnightOptionByKnightId</summary>
        /// <param name="KnightId"></param>
        /// <returns></returns>
        /// <history>created  21.02.2012</history>
        private XElement _getKnightOptionByKnightId(
            string KnightId)
        {
            try
            {
                XElement xeKnightOptions = _getFbUidServerIdNode();

                //get current Knightoptions for fbuid / server number combination
                IEnumerable<XElement> xeKnightList = _xeKnightOptions.Descendants(ELEMENT_KNIGHT).Where(
                    kntItem => string.Equals(kntItem.Attribute(ATTRIBUTE_KNIGHT_ID).Value, KnightId, StringComparison.OrdinalIgnoreCase));

                if (xeKnightList.Count() > 0)
                {
                    XElement xeKnight = xeKnightList.First();
                    return xeKnight;
                }
            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }

            return null;
        }

        /// <summary>_saveKnightOptions</summary>
        /// <history>created  20.02.2012</history>
        private void _saveKnightOptions()
        {
            try
            {
                if (_xeKnightOptions != null)
                {
                    XElement xeBaseNode = _getFbUidServerIdNode();

                    foreach (KnightViewItem KVI in _ocKnights)
                    {
                        XElement xeKnightOption = _getKnightOptionByKnightId(KVI.Knight.KnightId.ToString());

                        if (xeKnightOption != null &&
                            xeKnightOption.Attribute(ATTRIBUTE_SKILLUP) != null)
                        {
                            if (xeKnightOption.Attribute(ATTRIBUTE_SKILLUP).Value != _getKnightRoleOfItem(KVI).GetHashCode().ToString())
                            {
                                xeKnightOption.Attribute(ATTRIBUTE_SKILLUP).Value = _getKnightRoleOfItem(KVI).GetHashCode().ToString();
                            }
                        }
                        else
                        {
                            xeKnightOption = new XElement(ELEMENT_KNIGHT,
                                new XAttribute(ATTRIBUTE_KNIGHT_ID, KVI.Knight.KnightId.ToString()),
                                new XAttribute(ATTRIBUTE_KNIGHT_NAME, KVI.Knight.KnightName),
                                new XAttribute(ATTRIBUTE_SKILLUP, _getKnightRoleOfItem(KVI).GetHashCode().ToString())
                                    );

                            xeBaseNode.Add(xeKnightOption);
                        }
                    }

                    _laoKnightOptions.SetOptionXElement(_xeKnightOptions);
                }
            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }
        }
        #endregion

        #region skill up knights
        /// <summary>_skillUpKnights</summary>
        /// <history>created  21.02.2012</history>
        private void _skillUpKnights()
        {
            try
            {
                Thread thr = new Thread((ParameterizedThreadStart)delegate
                {

                });
                thr.Start();
            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }
        }
        #endregion
        #endregion



        #region interface
        #region properties
        public ICommand ReadKnights
        {
            get
            {
                if (_rcReadKnights == null)
                {
                    _rcReadKnights = new RelayCommand(
                        param => this._readKnights(),
                        param => this.CanReadKnights);
                }
                return _rcReadKnights;
            }
        }
        public Boolean CanReadKnights
        {
            get
            {
                return _fSeedExists;
            }
        }

        public ICommand ResetToDefaults
        {
            get
            {
                if (_rcResetToDefaults == null)
                {
                    _rcResetToDefaults = new RelayCommand(
                        param => this._readKnights(),
                        param => this.CanReadKnights);
                }
                return _rcResetToDefaults;
            }
        }
        public Boolean CanResetToDefaults
        {
            get
            {
                return _ocKnights.Count > 0;
            }
        }

        public ICommand SkillUpKnights
        {
            get
            {
                if (_rcSkillUpnights == null)
                {
                    _rcSkillUpnights = new RelayCommand(
                        param => this._skillUpKnights(),
                        param => this.CanReadKnights);
                }
                return _rcSkillUpnights;
            }
        }
        public Boolean CanSkillUpKnights
        {
            get
            {
                return _ocKnights.Count > 0;
            }
        }

        public ObservableCollection<KnightViewItem> Knights
        {
            get
            {
                return _ocKnights;
            }
        }
        #endregion

        #region methods
        #endregion
        #endregion
    }
}